﻿using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Wfxin.RabbitMQ;
using RabbitMQ.Client.Framing;

namespace Wfxin.Web.Api.MQ
{
    public interface IOrderPublishMessageSender : IPublishMessageSender
    {
        Task<dynamic> SendAsyncV2<T>(T info);
        Task<dynamic> SendAsync<T>(T info, string version);

    }

    internal class RabbitMQOrderPublishMessageSender : IOrderPublishMessageSender
    {
        private readonly IOrderConnectionChannelPool _connectionChannelPool;
        private readonly ILogger _logger;
        private readonly string _exchange;
        private readonly string _exchangeType;
        //private readonly IZDaDistributedRedisCache m_SECache = null;

        private readonly DistributedCacheEntryOptions m_DistributedCacheEntryOptions = new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(10) };

        public RabbitMQItem RabbitMQItem { get; private set; }

        public RabbitMQOrderPublishMessageSender(IOptions<RabbitMQOptions> options, ILogger<RabbitMQOrderPublishMessageSender> logger,
            IOrderConnectionChannelPool connectionChannelPool)//, IZDaDistributedRedisCache cache
        {
            this.RabbitMQItem = options.Value.Items.FirstOrDefault(o => o.Name.Equals("CreateOrder"));
            _logger = logger;
            _connectionChannelPool = connectionChannelPool;
            _exchange = _connectionChannelPool.Exchange;
            _exchangeType = _connectionChannelPool.ExchangeType;
            //m_SECache = cache;
        }

        public Task<dynamic> SendAsync<T>(T info)
        { 
            return this.SendAsync<T>(info, "");
        }

        public Task<dynamic> SendAsyncV2<T>(T info)
        {
            //string key = $"{this.RabbitMQItem.RouteKey}_v2";
            //string json = JsonConvert.SerializeObject(info);
            //return this.PublishAsync(key, Encoding.UTF8.GetBytes(json));
            return this.SendAsync<T>(info, "v2");
        }
        public Task<dynamic> SendAsync<T>(T info, string version)
        {
            string key = string.Join("_", this.RabbitMQItem.RouteKey, version);
            string json = Newtonsoft.Json.JsonConvert.SerializeObject(info);
            return this.PublishAsync(key, System.Text.Encoding.UTF8.GetBytes(json));
        }

        public Task<dynamic> PublishAsync(string keyName, byte[] body)
        {
            var channel = _connectionChannelPool.Rent();
            try
            { 
                IBasicProperties properties = channel.CreateBasicProperties();
                properties.DeliveryMode = 2;
                channel.ExchangeDeclare(_exchange, _exchangeType, true);
                channel.BasicPublish(exchange: _exchange, routingKey: keyName, basicProperties: properties, body: body);

                _logger.LogDebug($"RabbitMQ {_exchangeType} message [{keyName}] has been published.");

                return Task.FromResult<dynamic>(new { Success = true });
            }
            catch (Exception ex)
            {
                //将错误订单信息保存到缓存中
                //var task = this.m_SECache.SetAsync($"CreateOrder_{Guid.NewGuid().ToString("N")}", body, m_DistributedCacheEntryOptions)
                //    .ContinueWith<dynamic>(_ => new { Success = false, RCode = ex.HResult.ToString(), RMsg = ex.Message });
                //return task;
                return Task.FromResult<dynamic>(null);
                //return Task.FromResult<dynamic>(new { Success = false, RCode = ex.HResult.ToString(), RMsg = ex.Message });
            }
            finally
            {
                var returned = _connectionChannelPool.Return(channel);
                if (!returned)
                {
                    channel.Dispose();
                }
            }
        }

    }
}
